/***************************************************************************//**
 * @file softwareMultiTimer.c
 * @brief for low power timer decommand
 * @author ze .
 * @date  2022/6/30.
 * @copyright Copyright 
 ******************************************************************************/

#include "MultiTimer.h"
#include "softwareMultiTimer.h"

//#include "ds_bsp" 
//#include "em_lib" 
/****************Typedef here*****************************/

typedef struct 
{
    MULTITIMER_INST_ST instHardTimer;
    SYS_TICK_TIME_U    uHardTimertick;

}SOFTWARE_MULTIMER_ST;

/************extern function and data declare here************/

SYS_TICK_TIME_U getSoftwareTimerTick(LP_HARD_TIMER_TYPE_E eType);

/************static function and data declare here************/


static int overflowTimerCoutHandle(LP_HARD_TIMER_TYPE_E eType);

static uint64_t getEM3SysRtc0Tick(void);
static uint64_t getEM3SysRtc1Tick(void);
static uint64_t getEM4BuRtcTick(void);
static uint64_t getActiveTime0Tick(void);

static void newStartedSysRtc0 (MultiTimer* timer);
static void newStartedSysRtc1 (MultiTimer* timer);
static void newStartedBuRtc (MultiTimer* timer);
static void newStartedActiveTime0 (MultiTimer* timer);

static void stopSysRtc0 (MultiTimer* timer);
static void stopSysRtc1 (MultiTimer* timer);
static void stopBuRtc (MultiTimer* timer);
static void stopActiveTime0 (MultiTimer* timer);


//static data here
static SOFTWARE_MULTIMER_ST  pInstHardTimer[EN_LP_HARD_TIMER_MAX] =
{
    {
        .instHardTimer = 
            {
            .byHandle = EN_LP_HARD_TIMER_EM3_SYS_RTC,
            .isCriticalProtect = 1,
            .timerList = NULL,
            .sysTicksGetFunction = getEM3SysRtc0Tick,
            .timerNewStartedFunction = newStartedSysRtc0,
            .timerStopFunction = stopSysRtc0
            },
            
        .uHardTimertick.dlSysTick = (uint64_t)0
    },

    {
        .instHardTimer = 
            {
            .byHandle = EN_LP_HARD_TIMER_EM3_SYS_RTC_1,
            .isCriticalProtect = 1,
            .timerList = NULL,
            .sysTicksGetFunction = getEM3SysRtc1Tick,
            .timerNewStartedFunction = newStartedSysRtc1,
            .timerStopFunction = stopSysRtc1
            },
            
        .uHardTimertick.dlSysTick = (uint64_t)0
    },

    {
        .instHardTimer = 
            {
            .byHandle = EN_LP_HARD_TIMER_EM4_BU_RTC,    
            .isCriticalProtect = 1,        
            .timerList = NULL,
            .sysTicksGetFunction = getEM4BuRtcTick,
            .timerNewStartedFunction = newStartedBuRtc,
            .timerStopFunction = stopBuRtc
            },
            
        .uHardTimertick.dlSysTick = (uint64_t)0
    },

    {
        .instHardTimer = 
            { 
            .byHandle = EN_LP_HARD_TIMER_ACTIVE_TIMER0,    
            .isCriticalProtect = 1,       
            .timerList = NULL,
            .sysTicksGetFunction = getActiveTime0Tick,
            .timerNewStartedFunction = newStartedActiveTime0,
            .timerStopFunction = stopActiveTime0
            },   
        .uHardTimertick.dlSysTick = (uint64_t)0
    } 
};


/****************static function coding here***********************/


static uint64_t getEM3SysRtc0Tick(void)
{
    return getSoftwareTimerTick(EN_LP_HARD_TIMER_EM3_SYS_RTC).dlSysTick;
}

static uint64_t getEM3SysRtc1Tick(void)
{
    return getSoftwareTimerTick(EN_LP_HARD_TIMER_EM3_SYS_RTC_1).dlSysTick;    
}

static uint64_t getEM4BuRtcTick(void)
{
    return getSoftwareTimerTick(EN_LP_HARD_TIMER_EM4_BU_RTC).dlSysTick;      
}

static uint64_t getActiveTime0Tick(void)
{
    return getSoftwareTimerTick(EN_LP_HARD_TIMER_ACTIVE_TIMER0).dlSysTick;        
}

//使能定时器比较中断，新赋值比较值，Todo适配到硬件
static void newStartedSysRtc0 (MultiTimer* timer)
{
    sl_sysrtc_set_group_compare_channel_value(0u, 0u,(uint32_t)(timer->deadline));
    sl_sysrtc_enable_group_interrupts(0,SYSRTC_GRP0_IEN_CMP0); //默认开启sysRTC
}

static void newStartedSysRtc1 (MultiTimer* timer)
{
    sl_sysrtc_set_group_compare_channel_value(0u, 1u,(uint32_t)(timer->deadline));
    sl_sysrtc_enable_group_interrupts(0,SYSRTC_GRP0_IEN_CMP1); //默认开启sysRTC
}

static void newStartedBuRtc (MultiTimer* timer)
{
    BURTC_CompareSet(0, (uint32_t)(timer->deadline));
    BURTC_IntEnable(BURTC_IEN_COMP);    // compare match Int enable
    //printf("<");
}
static void newStartedActiveTime0 (MultiTimer* timer) // invalid now
{
    //startTimer(3,timer);

}

//关闭定时器比较中断，ToDO，需适配EFR32的硬件
static void stopSysRtc0 (MultiTimer* timer) 
{
    sl_sysrtc_disable_group_interrupts(0,SYSRTC_GRP0_IEN_CMP0); //默认开启sysRTC
}

static void stopSysRtc1 (MultiTimer* timer) 
{
    sl_sysrtc_disable_group_interrupts(0,SYSRTC_GRP0_IEN_CMP1); //默认开启sysRTC
}

static void stopBuRtc (MultiTimer* timer)
{
    BURTC_IntDisable(BURTC_IEN_COMP);    // compare match Int Disable
}
static void stopActiveTime0 (MultiTimer* timer)
{
    //stopTimer(3,timer);
}

//called by timer overflow interrupt callback. it's secure. 从中断服务程序内被调用， 需使用volatile关键字，不保证其原子性以实时更新
//ToDo 溢出时刻，overflow未加，在临界保护代码中 调用getTick函数将不准确？ 人为修改count 制造溢出情况!
static int overflowTimerCoutHandle(LP_HARD_TIMER_TYPE_E eType) 
{
    if(eType >= EN_LP_HARD_TIMER_MAX )
    {
        //printf("Error, timer type invalid:%d \r\n",eType);
        return -1;
    }
    pInstHardTimer[eType].uHardTimertick.rtcTime32.dwCarryTime ++; // the count is overflow,so carry needed.

    return 0;
}


void BURTC_IRQHandler(void)
{
  uint32_t irq_flag =  BURTC_IntGet();
  BURTC_IntClear(irq_flag);
  if(irq_flag & BURTC_IF_OF)
  {
      overflowTimerCoutHandle(EN_LP_HARD_TIMER_EM4_BU_RTC);
  }
  if(irq_flag & BURTC_IF_COMP)
  {
      //printf(">");
      softwareMultiTimerExpiredCheck(EN_LP_HARD_TIMER_EM4_BU_RTC); //handle the expire
  }

}

void SYSRTC_APP_IRQHandler(void)
{
  uint32_t irq_flag = sl_sysrtc_get_group_interrupts(0u);
  sl_sysrtc_clear_group_interrupts(0,irq_flag);
  if(irq_flag & SYSRTC_GRP0_IF_OVF)
  {
      overflowTimerCoutHandle(EN_LP_HARD_TIMER_EM3_SYS_RTC);
      overflowTimerCoutHandle(EN_LP_HARD_TIMER_EM3_SYS_RTC_1);
  }

  if(irq_flag & SYSRTC_GRP0_IF_CMP0)
  {
      softwareMultiTimerExpiredCheck(EN_LP_HARD_TIMER_EM3_SYS_RTC);
  }

  if(irq_flag & SYSRTC_GRP0_IF_CMP1)
  {
      softwareMultiTimerExpiredCheck(EN_LP_HARD_TIMER_EM3_SYS_RTC_1);
  }

}


/**
 * @brief get the Timer tick, for debug
 * 
 * @param eType in target hardTimer
 * @return MultiTimer*  listHead
 */
SYS_TICK_TIME_U getSoftwareTimerTick(LP_HARD_TIMER_TYPE_E eType)
{
    switch (eType)
    {
        case EN_LP_HARD_TIMER_EM3_SYS_RTC:
        {
            pInstHardTimer[eType].uHardTimertick.rtcTime32.dwCounter = sl_sysrtc_get_counter();//ToDo，需适配到EFR32的硬件屏蔽层
            break;
        }

        case EN_LP_HARD_TIMER_EM3_SYS_RTC_1:
        {
            pInstHardTimer[eType].uHardTimertick.rtcTime32.dwCounter = sl_sysrtc_get_counter();//
            break;
        }

        case EN_LP_HARD_TIMER_EM4_BU_RTC:
        {
            pInstHardTimer[eType].uHardTimertick.rtcTime32.dwCounter = BURTC_CounterGet();//
            break;
        }

        case EN_LP_HARD_TIMER_ACTIVE_TIMER0:
        {
            //pInstHardTimer[eType].uHardTimertick.rtcTime32.dwCounter = getTickCount();//
            break;
        }

    };

    return pInstHardTimer[eType].uHardTimertick;
}


/**
 * @brief Start the timer work, add the handle into work list.若isCriticalProtect == 0，则该函数仅能从while函数调用
 * 
 * @param eType in target hardTimer
 * @param timer in target handle strcut.
 * @param timing in Set the start time.
 * @param callback in deadline callback.
 * @param userData in user data.注意 必须是全局变量的指针
 * @param isRepeatCheck 是否对链表内重复的数据进行检测，否 以节约时间
 * @return int >0: idx, -1: fail.
 */
int softwareMultiTimerStart(LP_HARD_TIMER_TYPE_E eType, MultiTimer* timer, uint32_t timing, MultiTimerCallback_t callback, void* userData,uint8_t isRepeatCheck)
{
    //printf("[Debug]start timer%d, handle%d deadline%llu timing%lu\r\n",*((int*)timer->userData),timer->Handle,timer->deadline,timer->Time);
    return MultiTimerStart(&(pInstHardTimer[eType].instHardTimer),timer,timing,callback,userData,isRepeatCheck,0);
}

/**
 * @brief Start the timer work, add the handle into work list.若isCriticalProtect == 0，则该函数仅能从while函数调用TBD 确保deadline时间应远大于sysTick时间，若deadline小于将产生严重后果
 * 
 * @param eType in target hardTimer
 * @param timer in target handle strcut.
 * @param deadline in Set the deadline 结束的时间点 时刻，用于时分多址.TBD 确保deadline时间应远大于sysTick时间，若deadline小于将产生严重后果
 * @param callback in deadline callback.
 * @param userData in user data.注意 必须是全局变量的指针
 * @param isRepeatCheck 是否对链表内重复的数据进行检测，否 以节约时间
 * @return int 0: success, -1: fail.
 */
int softwareMultiTimeDeadlineStart(LP_HARD_TIMER_TYPE_E eType, MultiTimer* timer, uint64_t deadline, MultiTimerCallback_t callback, void* userData,uint8_t isRepeatCheck)
{
    return MultiTimerStart(&(pInstHardTimer[eType].instHardTimer),timer,deadline,callback,userData,isRepeatCheck,1);
}

/**
 * @brief Stop the timer work, remove the handle off work list.若isCriticalProtect == 0，则该函数仅能从while函数调用
 * 
 * @param eType in target hardTimer
 * @param timer target handle strcut.
 * @param isCallbackExpire 是否直接回调溢出函数
 * @return int 0: success, -1: fail.
 */
int softwareMultiTimerStop(LP_HARD_TIMER_TYPE_E eType, MultiTimer* timer,uint8_t isCallbackExpire)
{
    return MultiTimerStop(&(pInstHardTimer[eType].instHardTimer),timer, isCallbackExpire);
}

/**
 * @brief Stop the timer work, remove the handle off work list.若isCriticalProtect == 0，则该函数仅能从while函数调用
 * 
 * @param eType in target hardTimer
 * @param timer target handle strcut.
 * @return int >=0: idx ok, -1: fail.
 */
int softwareMultiTimerFind(LP_HARD_TIMER_TYPE_E eType, MultiTimer* timer)
{
    return MultiTimerFind(&(pInstHardTimer[eType].instHardTimer),timer);
}

/**
 * @brief Stop the timer work, remove all the handling work list.若isCriticalProtect == 0，则该函数仅能从while函数调用
 * 
 * @param eType in target hardTimer
 * @return int 0: success, -1: fail.
 */
int softwareMultiTimerStopAll(LP_HARD_TIMER_TYPE_E eType)
{
    return MultiTimerStopAll(&(pInstHardTimer[eType].instHardTimer));    
}

/**
 * @brief Check the timer expried and call callback. 若isCriticalProtect == 0，则该函数仅能从while函数调用
 * 
 * @param eType in target hardTimer
 * @return int The next timer expires.
 */
int softwareMultiTimerExpiredCheck(LP_HARD_TIMER_TYPE_E eType)
{
    return MultiTimerYield(&(pInstHardTimer[eType].instHardTimer));
}

/**
 * @brief software calibrate, for sysRtc only.
 * 
 * @param eType in target hardTimer
 * @param dwCalibrateValue in to calibrate value, max value 0 —— 0x00FFFFFF, 0x1FF=501s. when HUB ack packet received, the syncClock calibrate.
 * @param calibrateDirect 1 for +; 0 for -
 * @return int
 **/
int softwareMultiTimerCalibrate(LP_HARD_TIMER_TYPE_E eType, uint32_t dwCalibrateValue, uint8_t calibrateDirect) //TBD
{

}

/**
 * @brief get the Timer list head, for debug
 * 
 * @param eType in target hardTimer
 * @return MultiTimer*  listHead
 */
MultiTimer* getSoftwareMultiTimerListHead(LP_HARD_TIMER_TYPE_E eType)
{
    return pInstHardTimer[eType].instHardTimer.timerList;
}



